package chap_01_CompletableFuture.step_02_CompletableFuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @Description 常用API汇总：对计算结果进行处理
 * @Author shihan
 * @Date 2022/9/4 12:49
 * @Version 1.0
 */
public class CompletableStudy_04_API_02 {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newFixedThreadPool(3);

        //thenApply(executorService);
        handle(executorService);

        System.out.println("主线程继续执行...");

        executorService.shutdown();

    }

    /**
     * 计算结果之间存在依赖关系，后一个依赖前一个执行的结果（包括前一个的异常），两个线程之间串行处理
     * 异常处理：
     * 1、前一步的执行结果、异常都会传递给下一个步，中间某一步出现异常，并不会放弃后续步骤的执行；
     * 2、前一步执行没有异常，则执行结果作为第一个参数返回，第二个参数是异常信息此时就为null；
     * 3、前一步执行出现异常，传递到后一个步的第一个参数返回结果的值为null，第二个参数异常信息为具体的报错信息，并且后一步拿到这两个参数继续执行；
     * 3.1、后一步如果没有对异常进行判断处理，此时在这一步有可能还是会报异常，继续流转到下一层，直到 whenComplete 的前一个 handle 是否有异常；
     * 3.2、whenComplete 的前一个 handle 没有异常，正常执行 whenComplete 内容；
     * 3.3、whenComplete 的前一个 handle 有异常，exceptionally 只能处理最后一个 handle 中出现的异常，因为异常被一层一层覆盖掉了；
     * 3.4、并且中间步骤中出现的异常，没有对异常进行处理（判断/打印）等操作，异常信息是不会输出打印的，甚至里面出现异常了都不知道；
     * 4、因此 handle 的每一个步骤，都需要对第二个参数异常信息做非空判断，否则将会影响传递到下一步的第一个参数（上一步的返回值）
     *
     * @param executorService
     */
    private static void handle(ExecutorService executorService) {
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        }, executorService)
                // res = 1,e=null
                .handle((res, e) -> {
                    System.out.println("222");
                    int i = 10 / 0;
                    return res + 2;
                })
                // res=null,e=ArithmeticException
                .handle((res, e) -> {
                    System.out.println("333");
                    if (e != null) {
                        e.printStackTrace();
                        //如果改成return -1，这一步的返回值就正常返回为-1，并且也没有异常了
                        //return -1;
                        return res + 3;
                    } else {
                        // null+3 会报空指针异常
                        return res + 3;
                    }
                })
                // res=null,e=NullPointerException
                .handle((res, e) -> {
                    System.out.println("444");
                    if (e != null) {
                        e.printStackTrace();
                        return -1;
                    } else {
                        return res + 4;
                    }
                })
                // v=-1,e=null
                .whenComplete((v, e) -> {
                    if (e == null) {
                        System.out.println("最终的结果：" + v);
                    }
                })
                .exceptionally(e -> {
                    e.printStackTrace();
                    return null;
                });
    }

    /**
     * 计算结果之间存在依赖关系，后一个依赖前一个执行的结果，两个线程之间串行处理
     * 异常处理：中间某一步出现异常，直接进入 exceptionally 异常处理，后续的步骤不再执行
     *
     * @param executorService
     */
    private static void thenApply(ExecutorService executorService) {
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        }, executorService).thenApply(res -> {
            System.out.println("222");
            return res + 2;
        }).thenApply(res -> {
            int i = 10 / 0;
            System.out.println("333");
            return res + 3;
        }).thenApply(res -> {
            System.out.println("444");
            return res + 4;
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("最终的结果：" + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        });
    }

}
